package cn.jason.service.impl;

import cn.jason.domain.Goods;
import cn.jason.mapper.GoodsMapper;
import cn.jason.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @Author: Jason
 * @Date: 2022/9/19 18:53
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private JedisPool jedisPool;

    @Autowired
    private GoodsMapper goodsMapper;

    /**
     * 模拟多线程下单场景
     * 我们采用Redis的LUA脚本解决超卖问题
     */
    @Override
    public void insertOrder(Long goodsId) {
        String uuid = UUID.randomUUID().toString();
        Jedis jedis = jedisPool.getResource();
        Integer num = 2;//假如每个用户单次购买数量只能是2
        String result = jedis.set("123", uuid, "NX", "EX", 2);
        //获取锁并设置超时
        if("OK".equals(result)) {
            try{
                //操作数据库
                System.out.println("线程：[" + Thread.currentThread().getName() + "] 拿到锁了，开始做业务");
                //查询库存
                Goods goods = goodsMapper.laodById(goodsId);
                if (goods.getCount() >= num){
                    //库存足够，那么就开始扣减库存
                    Map<String,Object> params = new HashMap<>();
                    params.put("id", goodsId);
                    params.put("num", num);
                    goodsMapper.updateNum(params);//update t_goods set count=count-2 where id = 1
                    System.out.println("线程：[" + Thread.currentThread().getName() + "] 成功下单，库存扣减：" + num);
                }
                else{
                    System.out.println("线程：[" + Thread.currentThread().getName() + "] -----------拿到锁了，但库存不足，无法下单，很遗憾");
                }
            }finally {
                //lua脚本
                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
                //执行脚本
                jedis.eval(script, Collections.singletonList("123"), Collections.singletonList(uuid));
                jedis.close();
            }
        }
        else{
            System.out.println("线程：[" + Thread.currentThread().getName() + "] 没有拿到锁，无法扣减库存，开始自旋去获取锁");
            insertOrder(goodsId);
        }
    }
}
